Be reproducible, and don't fail on examples exceptions
authorDebian Science Maintainers <debian-science-maintainers@lists.alioth.debian.org>
Fri, 3 Jul 2026 21:13:01 +0000 (22:13 +0100)
committerRebecca N. Palmer <rebecca_palmer@zoho.com>
Fri, 3 Jul 2026 21:13:01 +0000 (22:13 +0100)
Don't execute example notebooks because some of them
have unreproducible output, either numerical differences (small
enough that I guess them to be machine-dependent rounding error
not deliberate randomness) or extra cells (a single newline
being split into its own cell vs part of the previous one).
Copy them instead.

At one point these 10 were affected, but skipping just them doesn't
work because it seems 'random' which ones have the extra cells.
count_hurdle
discrete_choice_example
discrete_choice_overview
exponential_smoothing (and its images 14_0 and 16_0)
generic_mle
glm_formula
glm_weights
postestimation_poisson
stats_poisson
treatment_effect

Also remove timestamps, ipykernel IDs, etc from examples output
for reproducibility.  (This is here not in debian/rules to do it
before building the search index.)

Skip some vector_ar cells that would print <type at address>
output (that would end up in the search index, so
stripping it afterwards isn't enough).

Author: Rebecca N. Palmer <rebecca_palmer@zoho.com>
Forwarded: not-needed

Gbp-Pq: Name sphinx_reproducibility_and_ignore_errors.patch

docs/Makefile
docs/source/conf.py
docs/source/vector_ar.rst
examples/notebooks/stl_decomposition.ipynb

index a77686dcd10e7f30df9933b6d8772f4478d1e934..edea6c11796ccc04e54029da7daeae64f39d3d9e 100644 (file)
@@ -16,6 +16,8 @@ NOTEBOOKBUILD = nbgenerate.py
 # Internal variables.
 PAPEROPT_a4     = -D latex_paper_size=a4
 PAPEROPT_letter = -D latex_paper_size=letter
+SOURCE_DATE:=$(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%a, %d %b %Y" || echo "xxx, xx xxx xxxx")
+SOURCE_TIME:=$(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%T" || echo "xx:xx:xx")
 
 # Put it first so that "make" without argument is like "make help".
 help:
@@ -33,7 +35,22 @@ html:
        @echo "Executing notebooks from examples/notebooks folder"
        mkdir -p $(BUILDDIR)/source/examples/notebooks/generated
        # Black list notebooks from doc build here
+ifeq ($(SOURCE_DATE_EPOCH),)
        $(TOOLSPATH)$(NOTEBOOKBUILD) --parallel --report-errors --skip-existing --execute-only --execution-blacklist statespace_custom_models
+endif
+       @echo "Copying notebooks that were not executed (for reproducibility) or failed execution (there are usually several in Debian because some need network and/or dependencies we don't have)"
+       cp -nav ../examples/notebooks/*.ipynb -t source/examples/notebooks/generated || true
+ifneq ($(SOURCE_DATE_EPOCH),)
+       @echo "Replacing timestamps and build paths in examples output for reproducibility"
+       for html in `find source/examples/notebooks/generated -name "*.html" -o -name "*.ipynb" -o -name "*.ipynb.txt"` ; do \
+           sed -i -e 's#$(PYTHONPATH)/statsmodels/#/usr/lib/python3/dist-packages/statsmodels/#g' \
+           -e 's# at 0x[0-9a-f]\{8,16\}\(&gt;\|>\)# at 0xadde5de1e8ed\1#g' \
+           -e 's#tmp/ipykernel_[0-9]\+#tmp/ipykernel_nnnnnnn#g' \
+           -e 's#^\s\+.\(iopub.execute_input\|iopub.status.busy\|iopub.status.idle\|shell.execute_reply\).:.*# #g' \
+           -e 's#\(Date:.*\)[A-Z][a-z]\+, \+[0-9]\+,\? \+[A-Z][a-z]\+,\? \+[0-9]\+#\1$(SOURCE_DATE)#g' \
+           -e 's#\(Time:.*\)[0-9][0-9]:[0-9][0-9]:[0-9][0-9]#\1$(SOURCE_TIME)#g' $${html} ; \
+       done
+endif
        @echo "Running sphinx-build"
        @echo @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(O)
        @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(O)
index 53ab2b440ab8026e2762d01292b63e62f86abd33..f3b25f6d6802a1d91a1c78fddb3066c1570204b8 100644 (file)
@@ -67,6 +67,7 @@ else:
 
 # nbsphinx options
 nbsphinx_allow_errors = True
+ipython_warning_is_error = False
 # sphinxcontrib-spelling options
 spelling_word_list_filename = ['spelling_wordlist.txt', 'names_wordlist.txt']
 spelling_ignore_pypi_package_names = True
index 6168d95622d5c86d3c7e861c313613f056b28ad1..7fe27743fd340ac2bc0df111194538ab2e2675e6 100644 (file)
@@ -127,6 +127,12 @@ likelihood test or information criteria-based order selection. We have
 implemented the latter, accessible through the :class:`VAR` class:
 
 .. ipython:: python
+   :suppress:
+
+   model.select_order(15)
+
+.. ipython:: python
+   :verbatim:
 
    model.select_order(15)
 
@@ -312,6 +318,7 @@ causality, but leave it to the reader. The :class:`VARResults` object has the
 F-test.
 
 .. ipython:: python
+   :verbatim:
 
    results.test_causality('realgdp', ['realinv', 'realcons'], kind='f')
 
@@ -326,6 +333,7 @@ are Gaussian white noise. To test whether this assumption is consistent with
 a data set, :class:`VARResults` offers the `test_normality` method.
 
 .. ipython:: python
+   :verbatim:
 
     results.test_normality()
 
index d2a429b12a801e55b6d9c53e2cdc59d6a4ebacec..e8d6eeeeed0a08c887106bac2999dba882b758e5 100644 (file)
    "outputs": [],
    "source": [
     "mod = STL(y, period=period, seasonal=seasonal)\n",
-    "%timeit mod.fit()\n",
+    "# removed for reproducibility: %timeit mod.fit()\n",
     "res = mod.fit()\n",
     "fig = res.plot(observed=False, resid=False)"
    ]
     "    trend_jump=trend_jump,\n",
     "    low_pass_jump=low_pass_jump,\n",
     ")\n",
-    "%timeit mod.fit()\n",
+    "# removed for reproducibility: %timeit mod.fit()\n",
     "res = mod.fit()\n",
     "fig = res.plot(observed=False, resid=False)"
    ]